#include "Core.h"

Core::Core(int fps)
{
	frame_ticks = 1000/fps;
	pantalla.Init(Dimensiones_t(640,480));
}

Core::~Core()
{}

void Core::Init()
{
	Main();
}

void Core::Salir()
{
	fsm.Parar();
	DesactivarAlarmas();
}

void Core::AgregarCallback(BaseCallback* callback)
{
	callbacks.insert(callback);
}

bool Core::EliminarCallback(BaseCallback* callback)
{
	callbacks.erase(callback);
}

void Core::AgregarAlarma(int llamadas, int tiempo, BaseCallback* _callback)
{
	Alarma* ptr = new Alarma(llamadas,tiempo,_callback);
	// cout << "nueva alarma: " << ptr << endl;
	alarmas.push_back(ptr);
}

Teclado& Core::Teclas()
{
	return teclas;
}

Pantalla_t& Core::Pantalla()
{
	return pantalla;
}

void Core::Main()
{
	bool quit = false;
	Timer timer;
	while (!quit)
	{
		/* Iniciar timer */
		timer.Start();

		/* Llamar todas las funciones subscriptas */
		forall(it,callbacks)
			(**it)();

		/* Reviso si alguna alarma se desactivo y la borro */
		RevisarAlarmas();

		/* Chequeo eventos sdl */
		SDL_Event event;
		while( SDL_PollEvent( &event ) )
		{
			if( event.type == SDL_QUIT )
				quit=true;
			else
				HandleKeyEvents(event);
		}

		/* Regular framerate */
		if( timer.GetTicks() < frame_ticks )
			SDL_Delay( frame_ticks-timer.GetTicks() );
	}
	
	Salir();
}

void Core::RevisarAlarmas()
{
	typeof(alarmas.begin()) it = alarmas.begin();
	while (it!=alarmas.end())
		if (!(*it)->Activa())
		{
			// cout << "eliminando alarma " << *it << endl;
			typeof(it) it2 = it;
			it++;
			delete *it2;
			alarmas.erase(it2);
		}
		else
		{
			it++;
		}
}

void Core::DesactivarAlarmas()
{
	typeof(alarmas.begin()) it = alarmas.begin();
	while (it!=alarmas.end())
	{
		// cout << "desactivando y eliminando alarma " << *it << endl;
		typeof(it) it2 = it;
		it++;
		(*it2)->Desactivar();
		delete *it2;
		alarmas.erase(it2);
	}

}

void Core::HandleKeyEvents(SDL_Event& event)
{
	if(event.type==SDL_KEYDOWN) switch( event.key.keysym.sym )
	{
		case SDLK_UP:
			teclas.al_tocar.arriba.Notificar();
			break;
		case SDLK_DOWN:
			teclas.al_tocar.abajo.Notificar();
			break;
		case SDLK_RIGHT:
			teclas.al_tocar.derecha.Notificar();
			break;
		case SDLK_LEFT:
			teclas.al_tocar.izquierda.Notificar();
			break;
		default:
			break;
	}
	else if(event.type==SDL_KEYUP) switch( event.key.keysym.sym )
	{
		case SDLK_UP:
			teclas.al_soltar.arriba.Notificar();
			break;
		case SDLK_DOWN:
			teclas.al_soltar.abajo.Notificar();
			break;
		case SDLK_RIGHT:
			teclas.al_soltar.derecha.Notificar();
			break;
		case SDLK_LEFT:
			teclas.al_soltar.izquierda.Notificar();
			break;
		default:
			break;
	}
}

FSM& Core::getFSM()
{
	return fsm;
}

Core* Core::instancia = new Core(FPS);

Core* Core::Instancia() { return instancia; }
